/* 
 * File:   Mundo.cpp
 * Author: 75.02 - Grupo 7, 2do cuatrimestre 2012.
 * 
 * Created on 31 de octubre de 2012, 18:47
 */

#include <sstream>

#include "Mundo.h"

#define NOMBRE_POR_DEFECTO "NO_NAME"

using namespace TP::Juego;

Mundo::Mundo() {
    _nombre = NOMBRE_POR_DEFECTO;
    _cantidadJugadores = 0;
}

Mundo::Mundo (const string& pNombre){
    this->_nombre = pNombre;
    this->_cantidadJugadores = 0;
}

Mundo::~Mundo() {
    for (unsigned int cur = 0; cur < _niveles.size(); cur++) {
            delete _niveles[cur];
    }
    this->_niveles.clear();
}

void Mundo::setNombre(const string& nombre) {
    _nombre = nombre;
}

const string& Mundo::getNombre() const {
    return _nombre;
}

void Mundo::setCantidadJugadores(unsigned cantidad) {
    _cantidadJugadores = cantidad;
}

unsigned Mundo::getCantidadJugadores() const {
    return _cantidadJugadores;
}

Nivel* Mundo::getNivel(unsigned idNivel) {
	
    Nivel* nivelReturn = NULL;

    int pos = obtenerPosicionNivel(idNivel);
    if (pos >= 0) 
        nivelReturn = _niveles[pos];

    return nivelReturn;
}

void Mundo::crearNivel(unsigned id, unsigned anchura, unsigned altura, unsigned tiempo, const std::string &rutaImagenFondo) {
	removerNivel(id);

	Nivel* nuevoNivel = new Nivel(id, anchura, altura, tiempo, rutaImagenFondo);
	if (nuevoNivel != NULL) {
		_niveles.push_back(nuevoNivel);
	}
}

bool Mundo::removerNivel(unsigned idNivel) {
	int pos = obtenerPosicionNivel(idNivel);

	if (pos >= 0) {
		delete _niveles[pos];
		_niveles.erase(_niveles.begin() + pos);
		return true;
	}
	return false;
}

bool Mundo::operator==(const Mundo &mundo) {
	return (_nombre == mundo._nombre);
}

bool Mundo::operator!=(const Mundo &mundo) {
	return (_nombre != mundo._nombre);
}

int Mundo::obtenerPosicionNivel(unsigned idNivel) {
	unsigned int pos = 0;
	unsigned int cantNiveles = _niveles.size();
	while ((pos < cantNiveles) && (idNivel != _niveles[pos]->getId())) {
		++pos;
	}

	if (pos < cantNiveles) {
		return pos;
	}
	return -1;
}


string Mundo::aXML(){

    TiXmlDocument* doc = new TiXmlDocument();
    TiXmlDeclaration * decl = new TiXmlDeclaration( "1.0", "", "" );
    doc->LinkEndChild( decl );
    
    doc->LinkEndChild(this->aElementoXML());

    TiXmlPrinter printer;
    doc->Accept(&printer);
    return printer.CStr();    
}

string Mundo::aXML(const string& pPath){

    TiXmlDocument* doc = new TiXmlDocument(pPath.c_str());
    TiXmlDeclaration * decl = new TiXmlDeclaration( "1.0", "", "" );
    doc->LinkEndChild( decl );
    
    doc->LinkEndChild(this->aElementoXML());
    
    TiXmlPrinter printer;
    doc->Accept(&printer);
    return printer.CStr();    
}

void Mundo::parseXML (const string& pDescriptor){

    TiXmlDocument doc;
    doc.Parse(pDescriptor.c_str(), 0, TIXML_ENCODING_UTF8);
    this->deElementoXML(doc.FirstChildElement());
}

TiXmlElement* Mundo::aElementoXML (){
    
    TiXmlElement * escenarioXML = new TiXmlElement("Mundo");

    escenarioXML->SetAttribute("nombre", this->_nombre.c_str());

    std::stringstream stream;
    stream << this->_cantidadJugadores;
    escenarioXML->SetAttribute("cantidad_jugadores", stream.str().c_str());
    
    // Serializo la lista de actores.
    TiXmlElement * niveles = new TiXmlElement("Niveles");
    
    for(size_t cur = 0; cur < this->_niveles.size(); ++cur) {
        niveles->LinkEndChild(this->_niveles[cur]->aElementoXML());
    }
    
    escenarioXML->LinkEndChild(niveles);
    
    return escenarioXML;
}

void Mundo::deElementoXML (TiXmlElement* pElemento){

    if (strcmp (pElemento->Value(), "Mundo") == 0)
    {
        this->_nombre = pElemento->Attribute("nombre");
        std::stringstream str(pElemento->Attribute("cantidad_jugadores"));
        str >> this->_cantidadJugadores;
        
        TiXmlElement * elemento = pElemento->FirstChildElement()->FirstChildElement();
        
        while(NULL != elemento) {
            Nivel *nivel = new Nivel();
            nivel->deElementoXML(elemento);
            this->_niveles.push_back(nivel);
            elemento = elemento->NextSiblingElement();
        }
    }
}

Mundo* Mundo::crearDeXML (const string& pDescriptor) throw (Excepcion&){

    TiXmlDocument doc;
    doc.Parse(pDescriptor.c_str(), 0, TIXML_ENCODING_UTF8);    
    
    if (strcmp (doc.FirstChildElement()->Value(), "Mundo") != 0)
        throw Excepcion ("El descriptor no corresponde a un objeto de clase Mundo.");
    
    Mundo* mundo = new Mundo();
    mundo->deElementoXML(doc.FirstChildElement());
    return mundo;
}
